/////////////////////////////////////////////////////////////////////////////
// Name:        batchencoder.cpp
// Purpose:     A class to convert a number of text files to WAV and then to
//              MP3.
// Author:      Julian Smart
// Modified by:
// Created:     2009-02-10
// RCS-ID:
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#include "wx/filename.h"
#include "wx/process.h"
#include "wx/txtstrm.h"
#include "wx/textfile.h"
#include "wx/datstrm.h"
#include "wx/wfstream.h"
#include "wx/frame.h"

#include "tts/tts_batchencoder.h"

/*
 * wxBatchTextToMP3Encoder implementation
 */

IMPLEMENT_DYNAMIC_CLASS( wxBatchTextToMP3Encoder, wxEvtHandler )

wxBatchTextToMP3Encoder::wxBatchTextToMP3Encoder()
{
    Init();
}

wxBatchTextToMP3Encoder::~wxBatchTextToMP3Encoder()
{
}

// Member initialisation
void wxBatchTextToMP3Encoder::Init()
{
    m_options = 0;
    m_verbosity = wxBATCHMP3ENCODER_VERBOSITY_ERRORS;
    //m_espeakOptions = 0;
    m_mp3EncoderOptions = 0;
    m_currentFile = -1;
    m_frame = NULL;
    m_statusField = 0;
    m_status = wxBATCHMP3ENCODER_STATUS_IDLE;
}

// Set data
bool wxBatchTextToMP3Encoder::SetData(const wxArrayString& textFilenames, const wxArrayString& audioFilenames, const wxID3InfoArray& infoArray)
{
    // TODO: checking
    m_textFilenames = textFilenames;
    m_outputFilenames = audioFilenames;
    m_infoArray = infoArray;

    return true;
}

// Encode the WAV and then the MP3
bool wxBatchTextToMP3Encoder::Start(int options, wxString* log)
{
    if (IsBusy())
        return false;

    if (m_textFilenames.GetCount() != m_outputFilenames.GetCount() && m_textFilenames.GetCount() != m_infoArray.GetCount())
        return false;

    if (m_textFilenames.GetCount() == 0)
        return false;

    m_status = wxBATCHMP3ENCODER_STATUS_STARTING;
    m_currentFile = -1;

    SetOptions(options);

    return Process(log);
}

// Stop encoding
bool wxBatchTextToMP3Encoder::Stop()
{
    if (m_textToSpeech.IsSpeaking())
    {
        m_textToSpeech.Stop();
    }
    else if (m_mp3Encoder.IsEncoding())
    {
        m_textToSpeech.Stop();
    }
    m_status = wxBATCHMP3ENCODER_STATUS_IDLE;
    return true;
}

// Check whether the next step should be done.
// If it returns false, the whole batch process has finished.
bool wxBatchTextToMP3Encoder::Process(wxString* log, bool* finished)
{
    if (log)
        *log = wxEmptyString;
    if (finished)
        *finished = false;

    if (m_status == wxBATCHMP3ENCODER_STATUS_IDLE)
        return false;

    if (m_textToSpeech.IsSpeaking())
    {
        m_textToSpeech.ProcessInput();

        return true;
    }

    if (m_mp3Encoder.IsEncoding())
    {
        m_textToSpeech.ProcessInput();

        return true;
    }

    bool generateMP3 = (GetOptions() & wxBATCHMP3ENCODER_OPTION_ENCODE_MP3) != 0;

    // Process the next file
    if ((m_status == wxBATCHMP3ENCODER_STATUS_STARTING) || (m_status == wxBATCHMP3ENCODER_STATUS_ENCODING_MP3) || !generateMP3)
    {
        m_currentFile ++;

        // Delete WAV file from previous iteration
        if (m_currentFile > 0)
        {
            wxString waveFilename(m_outputFilenames[m_currentFile-1]);
            wxTextToSpeech::StripExtension(waveFilename);
            waveFilename += wxT(".wav");

            wxString mp3Filename(m_outputFilenames[m_currentFile-1]);
            wxTextToSpeech::StripExtension(mp3Filename);
            mp3Filename += wxT(".mp3");

            // keep WAV files if not converting to MP3, or if MP3 creation failed.
            if (generateMP3 && wxFileExists(waveFilename) && wxFileExists(mp3Filename))
                wxRemoveFile(waveFilename);
        }

        if (m_currentFile >= (int) m_textFilenames.GetCount())
        {
            // We've finished
            m_status = wxBATCHMP3ENCODER_STATUS_IDLE;

            if (m_frame)
                m_frame->SetStatusText(_("Finished encoding files."), m_statusField);

            if (log)
                (*log) << _("Finished encoding files.");

            if (finished)
                *finished = true;

            return false;
        }

        m_status = wxBATCHMP3ENCODER_STATUS_TTS;
        wxString waveFilename(m_outputFilenames[m_currentFile]);
        wxTextToSpeech::StripExtension(waveFilename);
        waveFilename += wxT(".wav");

        // No, this results in no output.
        // m_espeakOptions |= wxESPEAK_OPTION_QUIET;

        if (m_frame)
        {
            wxString f(wxFileNameFromPath(waveFilename));
            wxString msg(wxString::Format(_("Creating WAV file %s (%d of %d)"), f.c_str(), (int) (m_currentFile+1), (int) m_textFilenames.GetCount()));
            m_frame->SetStatusText(msg, m_statusField);
        }

        if (m_textToSpeech.SpeakFile(m_textFilenames[m_currentFile], wxTTS_SPEAK_ASYNC, waveFilename))
        {
            if (log && (m_verbosity == wxBATCHMP3ENCODER_VERBOSITY_VERBOSE))
                (*log) << m_textToSpeech.GetLastCommand();

            return true;
        }
        else
        {
            // Something went wrong
            m_status = wxBATCHMP3ENCODER_STATUS_IDLE;

            wxString f(wxFileNameFromPath(waveFilename));
            wxString msg(wxString::Format(_("*** Sorry, could not create WAV file %s"), f.c_str()));

            if (m_frame)
            {
                m_frame->SetStatusText(msg, m_statusField);
            }

            if (log)
            {
                if (m_verbosity == wxBATCHMP3ENCODER_VERBOSITY_VERBOSE)
                    (*log) << m_textToSpeech.GetLastCommand() << wxT("\n");
                (*log) << msg;
            }

            return false;
        }
    }

    if (generateMP3 && m_status == wxBATCHMP3ENCODER_STATUS_TTS && !m_textToSpeech.IsSpeaking())
    {
        // We finished the TTS part, now do the MP3 encoding part
        m_status = wxBATCHMP3ENCODER_STATUS_ENCODING_MP3;
        wxString waveFilename(m_outputFilenames[m_currentFile]);
        wxTextToSpeech::StripExtension(waveFilename);
        waveFilename += wxT(".wav");

        wxString mp3Filename(m_outputFilenames[m_currentFile]);
        wxTextToSpeech::StripExtension(mp3Filename);
        mp3Filename += wxT(".mp3");

        m_mp3Encoder.SetID3(m_infoArray[m_currentFile]);
        m_mp3EncoderOptions |= wxMP3ENCODER_OPTION_ID3|wxMP3ENCODER_OPTION_QUIET;

        if (m_frame)
        {
            wxString f(wxFileNameFromPath(mp3Filename));
            wxString msg(wxString::Format(_("Creating MP3 file %s (%d of %d)"), f.c_str(), (int) (m_currentFile+1), (int) m_textFilenames.GetCount()));
            m_frame->SetStatusText(msg, m_statusField);
        }

        if (m_mp3Encoder.Encode(waveFilename, mp3Filename, m_mp3EncoderOptions))
        {
            if (log && (m_verbosity == wxBATCHMP3ENCODER_VERBOSITY_VERBOSE))
                (*log) << m_mp3Encoder.GetLastCommand();
            return true;
        }
        else
        {
            // Something went wrong
            m_status = wxBATCHMP3ENCODER_STATUS_IDLE;

            wxString f(wxFileNameFromPath(mp3Filename));
            wxString msg(wxString::Format(_("*** Sorry, could not create MP3 file %s"), f.c_str()));

            if (m_frame)
            {
                m_frame->SetStatusText(msg, m_statusField);
            }

            if (log)
            {
                if (m_verbosity == wxBATCHMP3ENCODER_VERBOSITY_VERBOSE)
                    (*log) << m_mp3Encoder.GetLastCommand() << wxT("\n");
                (*log) << msg;
            }

            return false;
        }
    }

    return false;
}
